Categories
Vue 3

Form Validation in a Vue 3 App with Vee-Validate 4 — Dynamic Forms and App Bundle Size

Spread the love

Form validation is an important part of any app.

In this article, we’ll look at how to use Vee-Validate 4 in our Vue 3 app for form validation.

Dynamic Form with Initial Values

We can set initial values for dynamic forms as we do with static forms.

To do this, we pass in an object with the values into the initial-values prop:

<template>
  <Form
    v-slot="{ errors }"
    :validation-schema="schema.validation"
    :initial-values="schema.values"
  >
    <div v-for="field in schema.fields" :key="field.name">
      <label :for="field.name">{{ field.label }}</label>
      <Field :as="field.as" :id="field.name" :name="field.name" />
      <span>{{ errors[field.name] }}</span>
    </div>

    <button>Submit</button>
  </Form>
</template>

<script>
import { Form, Field } from "vee-validate";
import * as yup from "yup";

export default {
  name: "DynamicForm",
  components: {
    Form,
    Field,
  },
  data() {
    return {
      schema: {
        fields: [
          {
            label: "Name",
            name: "name",
            as: "input",
          },
          {
            label: "Email",
            name: "email",
            as: "input",
          },
          {
            label: "Password",
            name: "password",
            as: "input",
          },
        ],
        validation: yup.object().shape({
          email: yup.string().email().required(),
          name: yup.string().required(),
          password: yup.string().min(8).required(),
        }),
        values: {
          name: "james",
          email: "abc@abc.com",
          password: "password",
        },
      },
    };
  },
};
</script>

We add the values property with the values into the schema reactive property.

Then we pass that into the validation-schema prop.

The property names of schema.values should match the values of the name prop of the field we want to fill in.

Now we should see the initial form values populated.

Reducing App Bundle Size

To reduce the bundle size of our app, we can selectively import the parts of the yup module we require.

For example, instead of writing:

<template>
  <Form
    v-slot="{ errors }"
    :validation-schema="schema.validation"
    :initial-values="schema.values"
  >
    <div v-for="field in schema.fields" :key="field.name">
      <label :for="field.name">{{ field.label }}</label>
      <Field :as="field.as" :id="field.name" :name="field.name" />
      <span>{{ errors[field.name] }}</span>
    </div>

    <button>Submit</button>
  </Form>
</template>

<script>
import { Form, Field } from "vee-validate";
import * as yup from "yup";

export default {
  name: "DynamicForm",
  components: {
    Form,
    Field,
  },
  data() {
    return {
      schema: {
        fields: [
          {
            label: "Name",
            name: "name",
            as: "input",
          },
          {
            label: "Email",
            name: "email",
            as: "input",
          },
          {
            label: "Password",
            name: "password",
            as: "input",
          },
        ],
        validation: yup.object().shape({
          email: yup.string().email().required(),
          name: yup.string().required(),
          password: yup.string().min(8).required(),
        }),
      },
    };
  },
};
</script>

We can write:

<template>
  <Form
    v-slot="{ errors }"
    :validation-schema="schema.validation"
    :initial-values="schema.values"
  >
    <div v-for="field in schema.fields" :key="field.name">
      <label :for="field.name">{{ field.label }}</label>
      <Field :as="field.as" :id="field.name" :name="field.name" />
      <span>{{ errors[field.name] }}</span>
    </div>

    <button>Submit</button>
  </Form>
</template>

<script>
import { Form, Field } from "vee-validate";
import { object, string } from "yup";

export default {
  name: "DynamicForm",
  components: {
    Form,
    Field,
  },
  data() {
    return {
      schema: {
        fields: [
          {
            label: "Name",
            name: "name",
            as: "input",
          },
          {
            label: "Email",
            name: "email",
            as: "input",
          },
          {
            label: "Password",
            name: "password",
            as: "input",
          },
        ],
        validation: object().shape({
          email: string().email().required(),
          name: string().required(),
          password: string().min(8).required(),
        }),
      },
    };
  },
};
</script>

We just import the object and string methods form the yup module, then we call them to create our schema.

Conclusion

We can add dynamic forms with initial values easily into our Vue 3 dynamic forms with Vee-Validate 4.

Also, we can reduce bundle size by selectively importing items from the yup module.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *